package com.ht.api.service;

import javax.sql.DataSource;

import com.ht.api.constant.CacheConstants;
import com.ht.api.db.Db;
import com.ht.api.db.DbConfig;
import com.ht.api.db.DbList;
import com.ht.api.db.Entity;
import com.ht.api.db.StreamLoadConfig;
import com.ht.api.db.exception.HtException;
import com.ht.api.db.util.RedisUtil;
import com.ht.api.open.OpenUtil;

import cn.hutool.core.date.DateUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * 应用消息推送service
 * @author asq
 * @createTime 2025年3月26日 14:49:28
 */
@Slf4j
public class AppmessageService {
	/** 接口ID：发送应用消息：通用 */
	private static final long API_ID_SEND = 1904793232626290688L;
	
	/**
	 * 创建消息
	 * @param ds 数据源
	 * @param param 消息参数
	 */
	public void create(DataSource ds, JSONObject param) {
		StreamLoadConfig config = DbConfig.getStreamLoadConfigByDataSource(ds);
		DbList list = DbList.create();
		
		// 主表
	 	JSONArray userArr = param.getJSONArray("user");
		Entity wxAppmessage = Db.createEntity("wx_appmessage");
		wxAppmessage.set("appid", param.getStr("appid"));
		wxAppmessage.set("user", JSONUtil.toJsonStr(userArr));
		wxAppmessage.set("msgtype", param.getStr("msgtype"));
		wxAppmessage.set("content", JSONUtil.toJsonStr(param.getStr("content")));
		wxAppmessage.set("status", 0);
		list.add(wxAppmessage);
		
		// 关联表
		for (int i = 0; i < userArr.size(); i++) {
			Entity wxAppmessageRelation = Db.createEntity("wx_appmessage_relation");
			wxAppmessageRelation.set("appmessage_id", wxAppmessage.getMainId());
			wxAppmessageRelation.set("userid", userArr.get(i));
			wxAppmessageRelation.set("is_interaction", 0);
			list.add(wxAppmessageRelation);
		}
		
		// 批量保存
		Db.insertBatchWithStream(config, list);
	}
	
	/**
	 * 修改消息
	 * @param ds 数据源
	 * @param param 消息参数
	 */
	public void update(DataSource ds, JSONObject param) {
		String mainId = param.getStr("mainId");
		Entity wxAppmessage = Db.createSqlParser("wx_appmessage").findById(ds, mainId);
		if (wxAppmessage == null) {
			throw new HtException("应用消息不存在：" + mainId);
		}
		if (wxAppmessage.getInt("status") == 1) {
			throw new HtException("应用消息已发送，不允许修改~");
		}
		if (wxAppmessage.getInt("status") == 2) {
			throw new HtException("应用消息已撤回，不允许修改~");
		}
		
		StreamLoadConfig config = DbConfig.getStreamLoadConfigByDataSource(ds);
		DbList list = DbList.create();
		
		// 删除旧的关联表
		JSONArray newUserArr = param.getJSONArray("user");
		DbList oldList = Db.createSqlParser("wx_appmessage_relation").where("appmessage_id", mainId).query(ds);
		oldList.stream().filter(old -> {
			return newUserArr.stream().noneMatch(newUser -> newUser.equals(old.getStr("userid")));
		}).forEach(oldRelation -> {
			oldRelation.set("sys_deleted", 0);
			list.add(oldRelation);
		});
		
		// 添加新的关联表
		newUserArr.stream().filter(newUser -> {
			return oldList.stream().noneMatch(old -> newUser.equals(old.getStr("userid")));
		}).forEach(newUser -> {
			Entity wxAppmessageRelation = Db.createEntity("wx_appmessage_relation");
			wxAppmessageRelation.set("appmessage_id", mainId);
			wxAppmessageRelation.set("userid", newUser);
			wxAppmessageRelation.set("is_interaction", 0);
			list.add(wxAppmessageRelation);
		});
		
		// 主表
		wxAppmessage.set("appid", param.getStr("appid"));
		wxAppmessage.set("user", JSONUtil.toJsonStr(newUserArr));
		wxAppmessage.set("msgtype", param.getStr("msgtype"));
		wxAppmessage.set("content", JSONUtil.toJsonStr(param.getStr("content")));
		list.add(wxAppmessage);
		
		// 批量保存
		Db.insertBatchWithStream(config, list);
	}
	
	/**
	 * 删除消息
	 * @param ds 数据源
	 * @param param 消息参数
	 */
	public void del(DataSource ds, String mainId) {
		Entity wxAppmessage = Db.createSqlParser("wx_appmessage").findById(ds, mainId);
		if (wxAppmessage == null) {
			throw new HtException("应用消息不存在：" + mainId);
		}
		if (wxAppmessage.getInt("status") == 1) {
			throw new HtException("应用消息已发送，不允许删除~");
		}
		if (wxAppmessage.getInt("status") == 2) {
			throw new HtException("应用消息已撤回，不允许删除~");
		}
		
		StreamLoadConfig config = DbConfig.getStreamLoadConfigByDataSource(ds);
		DbList list = DbList.create();
		
		// 主表
		wxAppmessage.set("sys_deleted", 0);
		list.add(wxAppmessage);
		
		// 关联表
		DbList relationList = Db.createSqlParser("wx_appmessage_relation").where("appmessage_id", mainId).query(ds);
		relationList.stream().forEach(r -> r.set("sys_deleted", 0));
		list.addAll(relationList);
		
		// 批量
		Db.insertBatchWithStream(config, list);
	}
	
	/**
	 * 发送消息
	 * @param ds 数据源
	 * @param mainId 消息mainId
	 */
	public void send(DataSource ds, String mainId) {
		Entity wxAppmessage = Db.createSqlParser("wx_appmessage").findById(ds, mainId);
		if (wxAppmessage == null) {
			throw new HtException("应用消息不存在：" + mainId);
		}
		if (wxAppmessage.getInt("status") == 1) {
			throw new HtException("应用消息已发送，请勿重复发送~");
		}
		
		// 调用企微接口，发送消息
		String appId = wxAppmessage.getStr("appid");
		String msgtype = wxAppmessage.getStr("msgtype");
		JSONObject wwxParam = JSONUtil.createObj();
		wwxParam.set("touser", wxAppmessage.getJSONArray("user"));
		wwxParam.set("msgtype", msgtype);
		wwxParam.set("agentid", getAgentid(appId));
		wwxParam.set(msgtype, wxAppmessage.getJSONObject("content"));
		wwxParam.set("safe", wxAppmessage.getInt("safe"));
		wwxParam.set("enable_id_trans", wxAppmessage.getInt("enable_id_trans"));
		wwxParam.set("enable_duplicate_check", wxAppmessage.getInt("enable_duplicate_check"));
		wwxParam.set("duplicate_check_interval", wxAppmessage.getInt("duplicate_check_interval"));
		String str = OpenUtil.call(appId, API_ID_SEND, wwxParam);
		
		// 本地数据库
		JSONObject obj = JSONUtil.parseObj(str);
		if (obj.getInt("errcode") == 0) {
			wxAppmessage.set("msgid", obj.getStr("msgid"));
			wxAppmessage.set("response_code", obj.getStr("response_code"));
			wxAppmessage.set("send_time", DateUtil.now());
			wxAppmessage.set("status", 1);
			Db.insert(ds, wxAppmessage);
			log.info("[AppmessageService]发送消息成功，main_id：{}", mainId);
		} else {
			log.error("[AppmessageService]发送消息失败，main_id：{}，企微接口返回错误：{}", mainId, obj.getStr("errmsg"));
			throw new HtException("企微接口返回错误：" + obj.getStr("errmsg"));
		}
	}
	
	/**
	 * 撤回消息
	 * @param ds 数据源
	 * @param mainId 消息mainId
	 */
	public void recall(DataSource ds, String mainId) {
		Entity wxAppmessage = Db.createSqlParser("wx_appmessage").findById(ds, mainId);
		if (wxAppmessage == null) {
			throw new HtException("应用消息不存在：" + mainId);
		}
		if (wxAppmessage.getInt("status") == 0) {
			throw new HtException("应用消息还未发送，勿须撤回~");
		}
		if (wxAppmessage.getInt("status") == 2) {
			throw new HtException("应用消息已撤回，请勿重复撤回~");
		}
		
		// 调用企微接口，撤回消息
		String appId = wxAppmessage.getStr("appid");
		String msgid = wxAppmessage.getStr("msgid");
		String str = OpenUtil.call(appId, API_ID_SEND, JSONUtil.createObj().set("msgid", msgid));
		
		// 本地数据库
		JSONObject obj = JSONUtil.parseObj(str);
		if (obj.getInt("errcode") == 0) {
			wxAppmessage.set("cancel_time", DateUtil.now());
			wxAppmessage.set("status", 2);
			Db.insert(ds, wxAppmessage);
			log.info("[AppmessageService]撤回消息成功，main_id：{}", mainId);
		} else {
			log.error("[AppmessageService]撤回消息失败，main_id：{}，企微接口返回错误：{}", mainId, obj.getStr("errmsg"));
			throw new HtException("企微接口返回错误：" + obj.getStr("errmsg"));
		}
	}
	
	/**
	 * 获取应用配置的agentid，即corpid
	 * @param appId
	 * @return
	 */
	private String getAgentid(String appId) {
		Entity app = RedisUtil.get(CacheConstants.KEY_APP + appId);
		JSONObject appConfig = JSONUtil.parseObj(app.getStr("config"));
		JSONArray tokenParamArr = appConfig.getJSONArray("token_param");
		for (int i = 0; i < tokenParamArr.size(); i++) {
			JSONObject tokenParam = tokenParamArr.getJSONObject(i);
			if ("corpid".equals(tokenParam.getStr("name"))) {
				return tokenParam.getStr("value");
			}
		}
		throw new HtException("应用未配置corpid");
	}
}
